using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace ConsolePlayer
{
	class ListManager
	{
		string listDataFile = string.Empty;
		static private ListManager _instance = null;
		static public ListManager Instance
		{
			get
			{
				if (_instance == null)
					_instance = new ListManager();
				return _instance;
			}
		}
		private ListManager()
		{
			listDataFile = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
			if (!listDataFile.EndsWith("\\"))
				listDataFile += "\\";
			listDataFile += "consoleplayer\\";
			DirectoryInfo dir = new DirectoryInfo(listDataFile);
			if (!dir.Exists)
				dir.Create();
			listDataFile += "list.dat";
			if (File.Exists(listDataFile))
			{
				FileStream fileStream = new FileStream(listDataFile, FileMode.Open, FileAccess.Read, FileShare.Read);
				BinaryFormatter b = new BinaryFormatter();//SoapFormatter
				playList = (Dictionary<int, string>)b.Deserialize(fileStream);
				if (playList == null)
					playList = new Dictionary<int, string>();
				fileStream.Close();

			}
			else
			{
				playList = new Dictionary<int, string>();
			}

			
		}
		private Dictionary<int, string> playList = null;

		public void Flush()
		{
			BinaryFormatter b=new BinaryFormatter();
			FileStream fileStream = new FileStream(listDataFile, FileMode.Create);
			b.Serialize(fileStream, playList);
			fileStream.Flush();
			fileStream.Close();
		}

		public int AddToList(string path)
		{
			if( playList.ContainsValue(path) )
			{
				return -1;
			}
			int count = playList.Count;
			playList.Add(count, path);
			return count;
		}

		public void ModifyList(int index, string path)
		{
			if( playList.ContainsKey(index) )
			{
				playList[index] = path;
			}
		}

		public void RmFromList(int index)
		{
			if( playList.ContainsKey(index) )
			{
				playList.Remove(index);
			}
		}

		public void DeleteList()
		{
			playList.Clear();
		}

		private Dictionary<int, string>.Enumerator enumerator;
		public  bool GetFirst(out KeyValuePair<int, string> item)
		{
			item = new KeyValuePair<int, string>();
			if (playList.Count == 0)
				return false;

			enumerator = playList.GetEnumerator();
			if (enumerator.MoveNext())
			{
				item = enumerator.Current;
				return true;
			}
			else
			{
				return false;
			}
		}

		public bool GetNext(out KeyValuePair<int, string> item)
		{
			item = new KeyValuePair<int, string>();
			if (enumerator.MoveNext())
			{
				item = enumerator.Current;
				return true;
			}
			else
			{
				return false;
			}

		}

		public bool GetAt(int index , out KeyValuePair<int, string> item)
		{
			item = new KeyValuePair<int, string>();
			if (playList.ContainsKey(index))
			{
				item = new KeyValuePair<int, string>(index, playList[index]);
				return true;
			}
			else
			{
				return false;
			}
		}

		public int GetCount()
		{
			return playList.Count;
		}
	}
	class CommandList : ICommand
	{
		PlayerArgs _args = null;
		public CommandList(PlayerArgs args)
		{
			_args = args;
		}
		#region ICommand Members

		public void Action()
		{
			KeyValuePair<int, string> item;
			bool result = ListManager.Instance.GetFirst(out item);
			while( result )
			{
				Console.Write(item.Key);
				Console.Write('\t');
				Console.Write(item.Value);
				Console.Write('\n');

				result = ListManager.Instance.GetNext(out item);
			}
		}

		#endregion
	}

	class CommandDeleteList : ICommand
	{
		PlayerArgs _args = null;
		public CommandDeleteList(PlayerArgs args)
		{
			_args = args;
		}
		#region ICommand Members

		public void Action()
		{
			ListManager.Instance.DeleteList();
		}

		#endregion
	}


	class CommandModifyList : ICommand
	{
		PlayerArgs _args = null;
		public CommandModifyList(PlayerArgs args)
		{
			_args = args;
		}

		#region ICommand Members

		public void Action()
		{
			ListManager.Instance.ModifyList((int)_args.modifyIndex, _args.destFile);
		}

		#endregion
	}

	class CommandAddToList : ICommand
	{
		private static string[] knowType = 
			{
				".mp3",
				".rmvb",
				".avi",
				".wav"
			};
		PlayerArgs _args = null;
		public CommandAddToList(PlayerArgs args)
		{
			_args = args;
		}

		#region ICommand Members

		public void Action()
		{
			if( _args.addDir )
			{
				AddDirToList(_args.destFile);
			}
			else
			{
				AddFileToList(_args.destFile, true) ;
			}
		}

		#endregion

		private void AddDirToList(string dir)
		{
			if (!dir.EndsWith("\\"))
				dir += "\\";
			DirectoryInfo info = new DirectoryInfo(dir);
			if (!info.Exists)
			{
				Console.WriteLine("no directory named " + dir + " exist!");
				return;
			}

			FileInfo[] files = info.GetFiles();
			foreach (FileInfo file in files)
			{
				AddFileToList(file.FullName, false);
			}

			DirectoryInfo[] dirs = info.GetDirectories();
			foreach (DirectoryInfo dirInfo in  dirs )
			{
				AddDirToList(dirInfo.FullName);
			}
		}

		private void AddFileToList(string path, bool showUnKnowType)
		{
			FileInfo info = new FileInfo(path);
			if( !info.Exists )
			{
				if( showUnKnowType )
					Console.WriteLine("no file named "+path+" exist!");
				return;
			}
			string extension = info.Extension;
			if( string.IsNullOrEmpty(extension) )
			{
				if (showUnKnowType)
					Console.WriteLine(path+" is not a file!");
				return;
			}
			if( !IsKnownType(extension ))
			{
				if (showUnKnowType)
					Console.WriteLine("do not know file type " + extension);
				return;
			}
			string fullPath = info.FullName;
			
			ListManager.Instance.AddToList(fullPath);
			Console.WriteLine("add file " + fullPath);
			
		}

		private bool IsKnownType(string extension)
		{
			string ext = extension.ToLower();
			foreach (string s in knowType)
			{
				if (ext == s)
					return true;
			}
			return false;
		}
	}

	class CommandRmFrmList : ICommand
	{
		PlayerArgs _args = null;
		public CommandRmFrmList(PlayerArgs args)
		{
			_args = args;
		}

		#region ICommand Members

		public void Action()
		{
			ListManager.Instance.RmFromList((int)_args.modifyIndex);
		}

		#endregion
	}
}
